package Modele;

import java.awt.*;
import java.util.List;
import java.util.Observable;
import java.util.Random;
import java.sql.Date;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MyCallable  extends Observable implements Callable<Double> {

	private String CallPutFlag;
	private double S;
	private double X;
	private double r;
	private double T;
	private double b;
	private double v;
	private int nSteps;
	private int nSimulations;

	public int getnSimulations() {
		return nSimulations;
	}

	public void setnSimulations(int nSimulations) {
		this.nSimulations = nSimulations;
	}

	private int couscous = 25;
	private double dt;
	private double St;
	private double Sum = 0;
	private double Drift;
	private double vSqrdt;

	private int z = 0;
	private Random rand;
	private int i;

	private double resultat1;
	
	public MyCallable(){}

	public MyCallable(String callPutFlag, double s, double x, double r,
			double t, double b, double v, int nSteps, int nSimulations) {

		this.CallPutFlag = callPutFlag;
		this.S = s;
		this.X = x;
		this.r = r;
		this.T = t;
		this.b = b;
		this.v = v;
		this.nSteps = nSteps;
		this.nSimulations = nSimulations;

		this.dt = T / nSteps;
		this.Drift = (b - v * v / 2) * dt;
		this.vSqrdt = v * java.lang.Math.sqrt(dt);
		if ("call".equals(this.CallPutFlag)) {
			this.z = 1;
		} else if ("putt".equals(this.CallPutFlag)) {
			this.z = -1;
		}

	}

	public Double call() throws Exception {

		rand = new Random();

		this.St = this.S;

		for (int l = 1; l <= this.nSteps; l++) {
			this.St = this.St
					* (java.lang.Math.exp(this.Drift + this.vSqrdt
							* this.rand.nextGaussian()));

		}

		this.Sum = this.Sum
				+ java.lang.Math.max(this.z * (this.St - this.X), 0);

		return (java.lang.Math.exp((-this.r * this.T)) * (this.Sum / this.nSimulations));
	}

	public void mycall() {

		int proc = Runtime.getRuntime().availableProcessors();

		System.out.println("Nombre de coeur : " + proc);

		// Get ExecutorService from Executors utility class, thread pool size is 10
		ExecutorService executor = Executors.newFixedThreadPool(proc);
		// create a list to hold the Future object associated with Callable
		List<Future<Double>> list = new ArrayList<Future<Double>>();
		// Create MyCallable instance
		Callable<Double> callable = new MyCallable(CallPutFlag, S, X, r, T, b,
				v, nSteps, nSimulations);

		long val = System.currentTimeMillis();

		for (this.i = 0; this.i <= this.nSimulations; this.i++) {
			setI(this.i);
			Future<Double> future = executor.submit(callable);
			list.add(future);
			setChanged();
			notifyObservers();
		}

		long val1 = System.currentTimeMillis();
		Future<Double> rree = list.get(nSimulations - 2);

		for (Future<Double> fut : list) {
			try {

				//System.out.println("r : " + fut.get());
				this.resultat1 = fut.get();
				setResultat1(fut.get());
				setChanged();
				notifyObservers();

			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		}

		System.out.println("resultat val2-val1: " + (val1-val));
		executor.shutdown();
	}
	
	public double getResultat1() {
		return resultat1;
	}

	public void setResultat1(double resultat1) {
		this.resultat1 = resultat1;
	}

	public int getI() {
		return i;
	}

	public void setI(int i) {
		this.i = i;
	}
	

}
